/**
 * PProduto.java
 * Copyright (C) 2009 Jose Mauro da Silva Sandy
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

package persistencia.produto;

import java.io.IOException;
import java.sql.*;
import plagio.postgres.ConnectionPostgres;
import negocio.produto.Produto;
import java.util.*;
import utils.*;

/**
 *
 * @author jmsandy
 */
public class PProduto {

    //<editor-fold defaultstate="collapsed" desc="Attributes">
    private boolean error = false;
    //</editor-fold>

    //<editor-fold defaultstate="collapsed" desc="Acessores">
    public boolean isError(){
        return this.error;
    }
    //</editor-fold>

    //<editor-fold defaultstate="collapsed" desc="Table Columns">
    static final protected String K_TBL_Produto        = "Produto";
    static final protected String K_COL_cod_objeto     = "cod_objeto";
    static final protected String K_COL_descricao      = "descricao";
    static final protected String K_COL_unid1          = "unid1";
    static final protected String K_COL_unid2          = "unid2";
    static final protected String K_COL_fatorConv      = "fatorconv";
    static final protected String K_COL_menorPreco     = "menorpreco";
    static final protected String K_COL_dtUltimaCompra = "dtUltimacompra";
    static final protected String K_COL_precoUltCompra = "precoultcompra";
    static final protected String K_COL_grupo          = "grupo";
    static final protected String K_COL_codProd        = "codprod";
    static final public int K_REC_COD_OBJETO           = 1;
    static final public int K_REC_COD_PRODUTO          = 2;
    //</editor-fold>

    //<editor-fold defaultstate="collapsed" desc="Constructor">
    /**
     * Construtor padrao. Responsavel por realizar a persistencia de um Produto
     * @throws java.io.IOException
     */
    public PProduto() throws IOException{
        error = false;
    }
    //</editor-fold>

    //<editor-fold defaultstate="collapsed" desc="Methods">
    // Realiza a construcao basica de um select
    private StringBuilder formSelector(){
        StringBuilder query = new StringBuilder();
        query.append("SELECT " + K_COL_cod_objeto + ", " + K_COL_descricao +
               ", " + K_COL_unid1 + ", " + K_COL_unid2 + " ," + K_COL_grupo +
               ", " + K_COL_fatorConv + ", " + K_COL_menorPreco + ", " +
               K_COL_dtUltimaCompra + ", " + K_COL_precoUltCompra + ", " +
               K_COL_codProd + " FROM " + "\"" + K_TBL_Produto + "\"");
        return query;
    }

    /**
     * Responsavel por criar a estrutura para inserir o objeto
     * @return construtor do objeto a ser inserido
     */
    private String formInsert(){
        return "INSERT INTO \"" + K_TBL_Produto + "\"(" + K_COL_cod_objeto +
           ", " + K_COL_descricao + ", " + K_COL_unid1 + ", " + K_COL_unid2 +
           ", " + K_COL_grupo + ", " + K_COL_fatorConv + ", " + K_COL_menorPreco
           + ", " + K_COL_dtUltimaCompra + ", " +  K_COL_precoUltCompra +
           ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
    }

    /**
     * Responsavel por criar a estrutura para atualizar o objeto
     * @param obj - Objeto a ser atualizado na base de dados
     * @return construtor do objeto a ser atualizado
     */
    private String formUpdate(Produto obj){
        StringBuilder query = new StringBuilder();
        query.append("UPDATE \"" + K_TBL_Produto + "\" SET " +
               K_COL_descricao + " = '"  + obj.getDescricao() + "', " +
               K_COL_unid1 + " = '"  + obj.getIdUnidade1() + "', " +
               K_COL_unid2 + " = '"  + obj.getIdUnidade2() + "', " +
               K_COL_grupo + " = '"  + obj.getIdGrupo() + "', " +
               K_COL_fatorConv + " = '"  + obj.getFatorConversao() + "', " +
               K_COL_menorPreco + " = '"  + obj.getMenorPreco() + "', " +
               K_COL_precoUltCompra + " = '"  + obj.getPrecoUltCompra() + "' ");

        // Verifica se foi informada alguma data
        if(obj.getDataUltCompra() != null){
            query.append(", " + K_COL_dtUltimaCompra + " = '"  +
                                        obj.getDataUltCompra() + "' ");
        }


        query.append("WHERE " + K_COL_cod_objeto + " = '" +
                                        obj.getCod_objeto() + "'");

        return query.toString();
    }

    /**
     * Responsavel por criar a estrutura para deletar o objeto
     * @param obj - Objeto a ser deletado na base de dados
     * @return construtor do objeto a ser deletado
     */
    private String formDelete(Produto obj){
        return "DELETE FROM \"" + K_TBL_Produto + "\" WHERE " + K_COL_cod_objeto
                + " = '" + obj.getCod_objeto() + "'";
    }

    /**
     * Responsavel por inserir um objeto na base de dados
     * @param obj - objeto a ser inserido na base de dados
     * @return TRUE - caso afirmativo e FALSE - caso contrario
     */
    public Boolean insert(Produto obj){
        Boolean status = true;

        try{
            ConnectionPostgres conn = new ConnectionPostgres(); // nova conexao

            // Realiza a conexao com o servidor
            conn = ConnectionSystem.connectionSystem();

            // Monta o objeto em uma instrucao SQL para insercao no banco
            PreparedStatement stat;
            String query = formInsert();
            stat = conn.getConnection().prepareStatement(query);
            stat.setString(1, obj.getCod_objeto());
            stat.setString(2, obj.getDescricao());
            stat.setString(3, obj.getIdUnidade1());
            stat.setString(4, obj.getIdUnidade2());
            stat.setString(5, obj.getIdGrupo());
            stat.setDouble(6, obj.getFatorConversao());
            stat.setDouble(7, 0);
            stat.setDate(8, null);
            stat.setDouble(9, 0);
            stat.executeUpdate();
            stat.close();
            conn.closeConnection();
        }
        catch(Exception ex){
            Log.gravarLog(RedirectStackTrace.stackTraceToString(ex), this);
            status = false;
        }
        return status;
    }

    /**
     * Responsavel por atualizar um objeto na base de dados
     * @param obj - objeto a ser atualizado na base de dados
     * @return TRUE - caso afirmativo e FALSE - caso contrario
     */
    public Boolean update(Produto obj){
        Boolean status = true;

        try{
            ConnectionPostgres conn = new ConnectionPostgres(); // nova conexao

            // Realiza a conexao com o servidor
            conn = ConnectionSystem.connectionSystem();

            // Monta o objeto em uma instrucao SQL para atualizacao no banco
            PreparedStatement stat;
            String query = formUpdate(obj);
            stat = conn.getConnection().prepareStatement(query);
            stat.executeUpdate();
            stat.close();
            conn.closeConnection();
        }
        catch(Exception ex){
            Log.gravarLog(RedirectStackTrace.stackTraceToString(ex), this);
            status = false;
        }
        return status;
    }

    /**
     * Responsavel por atualizar uma lista de produtos
     * @param lstProdutos lista de produtos que serao atualizados
     * @return TRUE caso afirmativo e FALSE - caso contrario
     */
    public Boolean atualizLista(ArrayList<Produto> lstProdutos){
        Boolean status = true;
        ConnectionPostgres conn = new ConnectionPostgres(); // nova conexao

        try{
            // Realiza a conexao com o servidor
            conn = ConnectionSystem.connectionSystem();
            conn.getConnection().setAutoCommit(false);
            // Monta o objeto em uma instrucao SQL para atualizacao no banco
            PreparedStatement stat = null;

            for(Produto prod : lstProdutos){
                String query = formUpdate(prod);
                stat = conn.getConnection().prepareStatement(query);
                stat.executeUpdate();
            }

            stat.close();
            stat.getConnection().commit();
        }
        catch(Exception ex){
            Log.gravarLog(RedirectStackTrace.stackTraceToString(ex), this);
            status = false;
        }
        finally{
            conn.closeConnection();
        }
        return status;
    }

    /**
     * Responsavel por deletar um objeto na base de dados
     * @param obj - objeto a ser deletado na base de dados
     * @return TRUE - caso afirmativo e FALSE - caso contrario
     */
    public Boolean delete(Produto obj){
        Boolean status = true;

        try{
            ConnectionPostgres conn = new ConnectionPostgres(); // nova conexao

            // Realiza a conexao com o servidor
            conn = ConnectionSystem.connectionSystem();

            // Monta o objeto em uma instrucao SQL para atualizacao no banco
            PreparedStatement stat;
            String query = formDelete(obj);
            stat = conn.getConnection().prepareStatement(query);
            stat.executeUpdate();
            stat.close();
            conn.closeConnection();
        }
        catch(Exception ex){
            Log.gravarLog(RedirectStackTrace.stackTraceToString(ex), this);
            status = false;
        }
        return status;
    }

    /**
     * Recupera um objeto produto pelo codigo de produto informado
     * @param codProd codigo do produto a ser procurado
     * @param tipo tipo a ser procurado
     * @return o produto encontrado ou NULL
     */
    public Produto refresh(String codProd, int tipo){
        Produto prod = new Produto(); // objeto de retorno

        StringBuilder query = this.formSelector();
        // Clausula wherecodigo do produto a ser procurado
        query.append(" WHERE " + (tipo == K_REC_COD_PRODUTO ? 
                                 K_COL_codProd + " = " + codProd + "" :
                                 K_COL_cod_objeto + " = '" + codProd + "'"));
        try{
            ConnectionPostgres conn = new ConnectionPostgres(); // nova conexao

            // Realiza a conexao com o servidor
            conn = ConnectionSystem.connectionSystem();

            Statement stat = conn.getConnection().createStatement();

            // Verifica a existencia do registro de retorno
            ArrayList<Produto> lstProdutos = new ArrayList<Produto>();
            lstProdutos = mapear(stat.executeQuery(query.toString()));
            if(lstProdutos.size() > 0) prod = lstProdutos.get(0);
            else prod = null;

        }catch(Exception ex){
            Log.gravarLog(RedirectStackTrace.stackTraceToString(ex), this);
            error = true;
            prod = null;
        }
        return prod;
    }

    /**
     * Recupera o ultimo codigo de produto inserido
     */
    public Integer recUltCodigo(){
        Integer valRet = 0;             // valor de retorno

        StringBuilder query = this.formSelector();
        // Clausula where
        query.append(" ORDER BY " + K_COL_codProd + " DESC");

        try{
            ConnectionPostgres conn = new ConnectionPostgres(); // nova conexao

            // Realiza a conexao com o servidor
            conn = ConnectionSystem.connectionSystem();

            Statement stat = conn.getConnection().createStatement();

            // Verifica a existencia do registro de retorno
            ArrayList<Produto> lstProdutos = new ArrayList<Produto>();
            lstProdutos = mapear(stat.executeQuery(query.toString()));
            if(lstProdutos.size() > 0){
                Produto prod = new Produto();
                prod = lstProdutos.get(0);
                valRet = prod.getCodProd();
            }
        }catch(Exception ex){
            Log.gravarLog(RedirectStackTrace.stackTraceToString(ex), this);
            valRet = 0;
        }
        return valRet;
    }

    /**
     * Responsavel por recuperar uma lista de todos os objetos que satisfacam
     * as condicoes recebidas para o objeto - descricao e grupo
     * @param produto: caracteristicas do produto a ser produrado
     * @return lista contendo todos os objetos recuperados
     */
    public ArrayList<Produto> recLstProdutos(Produto produto){
        // Lista de objetos de retorno
        ArrayList<Produto> lstProdutos = new ArrayList<Produto>();
        StringBuilder query = this.formSelector();
        // Clausula where
        query.append(" WHERE " + K_COL_descricao + " LIKE '");
        query.append(produto.getDescricao() + "%' AND " + K_COL_grupo);
        query.append(" LIKE '" + produto.getIdGrupo() + "%'");
        // Clausula order by
        query.append(" ORDER BY " +  K_COL_descricao );

        try{
            ConnectionPostgres conn = new ConnectionPostgres(); // nova conexao

            // Realiza a conexao com o servidor
            conn = ConnectionSystem.connectionSystem();

            Statement stat = conn.getConnection().createStatement();
            lstProdutos =  mapear(stat.executeQuery(query.toString()));
        }catch(Exception ex){
            Log.gravarLog(RedirectStackTrace.stackTraceToString(ex), this);
            error = true;
            lstProdutos = null;
        }
        return lstProdutos;
    }

    /**
     * Verifica se o produto a ser excluido esta vinculado a algum item
     * @param idProduto identificador do produto
     * @return TRUE se existe algum vinculo e FALSE caso contrario
     */
    public Boolean existsItem(String idProduto){
        Boolean ret = false;
        try{
            StringBuilder query = new StringBuilder();
            query = formSelector();
            query.append(" WHERE " + K_COL_cod_objeto + " IN (SELECT ");
            query.append("produto FROM \"Item\" WHERE produto = '");
            query.append(idProduto + "')");

            ConnectionPostgres conn = new ConnectionPostgres(); // nova conexao

            // Realiza a conexao com o servidor
            conn = ConnectionSystem.connectionSystem();
            Statement stat = conn.getConnection().createStatement();
            ret = stat.executeQuery(query.toString()).next();
        }catch(Exception ex){
            Log.gravarLog(RedirectStackTrace.stackTraceToString(ex), this);
            error = true;
        }
        return ret;
    }

    /**
     * Responsavel por converter o objeto vindo do banco de dados para um
     * modelo de objeto
     * @param result - result que obtem toda lista recebida do servidor
     * @return os objetos mapeados
     * @throws java.sql.SQLException
     */
    private ArrayList<Produto> mapear(ResultSet result) throws SQLException{
        ArrayList<Produto> lstProdutos = new ArrayList<Produto>();

        // Converte todo result recebido para uma lista de objetos
        while(result.next()){
            Produto produto = new Produto();
            produto.setCod_objeto(result.getString(1));
            produto.setDescricao(result.getString(2));
            produto.setIdUnidade1(result.getString(3));
            produto.setIdUnidade2(result.getString(4));
            produto.setIdGrupo(result.getString(5));
            produto.setFatorConversao(result.getDouble(6));
            produto.setMenorPreco(result.getDouble(7));
            produto.setDataUltCompra(result.getDate(8));
            produto.setPrecoUltCompra(result.getDouble(9));
            produto.setCodProd(result.getInt(10));
            produto.setIsNew(false);

            lstProdutos.add(produto);
        }
        return lstProdutos;
    }
    //</editor-fold>
}